import time
import logging
import json
from django.utils.deprecation import MiddlewareMixin
from django.http import JsonResponse
from django.core.cache import cache
from django.conf import settings
from django.utils import timezone
from .models import PerformanceMetric, ErrorLog, AuditLog
from .security import audit_logger

logger = logging.getLogger(__name__)


class PerformanceMonitoringMiddleware(MiddlewareMixin):
    """性能监控中间件"""
    
    def process_request(self, request):
        """请求开始时记录时间"""
        request._start_time = time.time()
        return None
    
    def process_response(self, request, response):
        """请求结束时记录性能指标"""
        if hasattr(request, '_start_time'):
            duration = time.time() - request._start_time
            
            # 记录性能指标
            try:
                PerformanceMetric.objects.create(
                    metric_name='request_duration',
                    metric_value=duration,
                    metric_unit='seconds',
                    tags={
                        'method': request.method,
                        'path': request.path,
                        'status_code': response.status_code,
                        'user': request.user.username if request.user.is_authenticated else 'anonymous'
                    }
                )
            except Exception as e:
                logger.error(f"Failed to record performance metric: {e}")
            
            # 如果响应时间过长，记录警告
            slow_threshold = getattr(settings, 'SLOW_REQUEST_THRESHOLD', 2.0)
            if duration > slow_threshold:
                logger.warning(
                    f"Slow request detected: {request.method} {request.path} "
                    f"took {duration:.2f}s (user: {request.user.username if request.user.is_authenticated else 'anonymous'})"
                )
        
        return response
    
    def process_exception(self, request, exception):
        """处理异常时记录错误日志"""
        try:
            import traceback
            
            ErrorLog.objects.create(
                error_type=exception.__class__.__name__,
                error_message=str(exception),
                stack_trace=traceback.format_exc(),
                request_path=request.path,
                request_method=request.method,
                user=request.user if request.user.is_authenticated else None,
                ip_address=self.get_client_ip(request),
                user_agent=request.META.get('HTTP_USER_AGENT', ''),
                extra_data={
                    'request_data': self.get_request_data(request),
                    'headers': dict(request.headers)
                }
            )
        except Exception as e:
            logger.error(f"Failed to record error log: {e}")
        
        return None
    
    def get_client_ip(self, request):
        """获取客户端IP地址"""
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            return x_forwarded_for.split(',')[0].strip()
        return request.META.get('REMOTE_ADDR')
    
    def get_request_data(self, request):
        """获取请求数据（安全处理）"""
        try:
            if request.method == 'GET':
                return dict(request.GET)
            elif request.method == 'POST':
                # 过滤敏感字段
                sensitive_fields = ['password', 'token', 'secret', 'key']
                data = {}
                
                if hasattr(request, 'POST'):
                    for key, value in request.POST.items():
                        if any(field in key.lower() for field in sensitive_fields):
                            data[key] = '***FILTERED***'
                        else:
                            data[key] = value
                
                return data
        except Exception:
            return {}


class SecurityMiddleware(MiddlewareMixin):
    """安全中间件"""
    
    def process_request(self, request):
        """请求安全检查"""
        # IP白名单检查
        if hasattr(settings, 'ALLOWED_IPS'):
            client_ip = self.get_client_ip(request)
            if client_ip not in settings.ALLOWED_IPS:
                logger.warning(f"Access denied for IP: {client_ip}")
                return JsonResponse({
                    'success': False,
                    'message': '访问被拒绝'
                }, status=403)
        
        # 请求大小限制
        content_length = request.META.get('CONTENT_LENGTH')
        if content_length:
            max_size = getattr(settings, 'MAX_REQUEST_SIZE', 10 * 1024 * 1024)  # 10MB
            if int(content_length) > max_size:
                logger.warning(f"Request too large: {content_length} bytes")
                return JsonResponse({
                    'success': False,
                    'message': '请求数据过大'
                }, status=413)
        
        return None
    
    def process_response(self, request, response):
        """添加安全响应头"""
        # 安全响应头
        response['X-Content-Type-Options'] = 'nosniff'
        response['X-Frame-Options'] = 'DENY'
        response['X-XSS-Protection'] = '1; mode=block'
        response['Referrer-Policy'] = 'strict-origin-when-cross-origin'
        
        # CORS处理
        if hasattr(settings, 'CORS_ALLOWED_ORIGINS'):
            origin = request.META.get('HTTP_ORIGIN')
            if origin in settings.CORS_ALLOWED_ORIGINS:
                response['Access-Control-Allow-Origin'] = origin
                response['Access-Control-Allow-Credentials'] = 'true'
                response['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
                response['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
        
        return response
    
    def get_client_ip(self, request):
        """获取客户端IP地址"""
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            return x_forwarded_for.split(',')[0].strip()
        return request.META.get('REMOTE_ADDR')


class CacheMiddleware(MiddlewareMixin):
    """缓存中间件"""
    
    def process_request(self, request):
        """检查缓存"""
        # 只对GET请求进行缓存
        if request.method != 'GET':
            return None
        
        # 跳过需要认证的请求
        if request.user.is_authenticated:
            return None
        
        # 生成缓存键
        cache_key = self.get_cache_key(request)
        cached_response = cache.get(cache_key)
        
        if cached_response:
            # 更新缓存统计
            self.update_cache_stats(cache_key, 'hit')
            
            # 返回缓存的响应
            response = JsonResponse(cached_response)
            response['X-Cache'] = 'HIT'
            return response
        
        # 缓存未命中
        self.update_cache_stats(cache_key, 'miss')
        request._cache_key = cache_key
        return None
    
    def process_response(self, request, response):
        """缓存响应"""
        if hasattr(request, '_cache_key') and response.status_code == 200:
            try:
                # 只缓存JSON响应
                if response.get('Content-Type', '').startswith('application/json'):
                    cache_timeout = getattr(settings, 'CACHE_TIMEOUT', 300)  # 5分钟
                    cache.set(request._cache_key, response.content, cache_timeout)
                    response['X-Cache'] = 'MISS'
            except Exception as e:
                logger.error(f"Failed to cache response: {e}")
        
        return response
    
    def get_cache_key(self, request):
        """生成缓存键"""
        return f"api_cache:{request.path}:{request.GET.urlencode()}"
    
    def update_cache_stats(self, cache_key, action):
        """更新缓存统计"""
        try:
            from .models import CacheStats
            stats, created = CacheStats.objects.get_or_create(cache_key=cache_key)
            
            if action == 'hit':
                stats.hit_count += 1
            elif action == 'miss':
                stats.miss_count += 1
            
            stats.save()
        except Exception as e:
            logger.error(f"Failed to update cache stats: {e}")


class AuditMiddleware(MiddlewareMixin):
    """审计中间件"""
    
    def process_request(self, request):
        """记录请求开始"""
        request._audit_start_time = timezone.now()
        return None
    
    def process_response(self, request, response):
        """记录审计日志"""
        # 只记录重要的API操作
        if self.should_audit(request):
            try:
                duration = None
                if hasattr(request, '_audit_start_time'):
                    duration = (timezone.now() - request._audit_start_time).total_seconds()
                
                AuditLog.objects.create(
                    user=request.user if request.user.is_authenticated else None,
                    action=f"{request.method} {request.path}",
                    resource_type=self.get_resource_type(request.path),
                    resource_id=self.get_resource_id(request),
                    result='success' if 200 <= response.status_code < 400 else 'error',
                    details={
                        'method': request.method,
                        'path': request.path,
                        'status_code': response.status_code,
                        'duration': duration,
                        'ip_address': self.get_client_ip(request),
                        'user_agent': request.META.get('HTTP_USER_AGENT', '')
                    },
                    ip_address=self.get_client_ip(request),
                    user_agent=request.META.get('HTTP_USER_AGENT', '')
                )
            except Exception as e:
                logger.error(f"Failed to record audit log: {e}")
        
        return response
    
    def should_audit(self, request):
        """判断是否需要审计"""
        # 审计的路径模式
        audit_patterns = [
            '/api/cmdb/',
            '/api/monitoring/',
            '/api/ssh/',
            '/api/auth/login/',
            '/api/auth/logout/'
        ]
        
        # 跳过GET请求（除了敏感操作）
        if request.method == 'GET' and not any(pattern in request.path for pattern in ['/api/ssh/', '/api/auth/']):
            return False
        
        return any(pattern in request.path for pattern in audit_patterns)
    
    def get_resource_type(self, path):
        """从路径获取资源类型"""
        if '/cmdb/hosts/' in path:
            return 'host'
        elif '/cmdb/environments/' in path:
            return 'environment'
        elif '/monitoring/' in path:
            return 'monitoring'
        elif '/ssh/' in path:
            return 'ssh'
        elif '/auth/' in path:
            return 'auth'
        return 'unknown'
    
    def get_resource_id(self, request):
        """从请求获取资源ID"""
        try:
            # 从URL路径中提取ID
            path_parts = request.path.strip('/').split('/')
            for i, part in enumerate(path_parts):
                if part.isdigit() or (len(part) == 36 and '-' in part):  # UUID格式
                    return part
            
            # 从请求参数中获取
            if hasattr(request, 'resolver_match') and request.resolver_match:
                return request.resolver_match.kwargs.get('pk')
        except Exception:
            pass
        
        return None
    
    def get_client_ip(self, request):
        """获取客户端IP地址"""
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            return x_forwarded_for.split(',')[0].strip()
        return request.META.get('REMOTE_ADDR')


class HealthCheckMiddleware(MiddlewareMixin):
    """健康检查中间件"""
    
    def process_request(self, request):
        """处理健康检查请求"""
        if request.path == '/health/':
            try:
                # 检查数据库连接
                from django.db import connection
                with connection.cursor() as cursor:
                    cursor.execute("SELECT 1")
                
                # 检查缓存
                cache.set('health_check', 'ok', 10)
                cache_status = cache.get('health_check') == 'ok'
                
                # 检查Celery
                celery_status = self.check_celery()
                
                health_data = {
                    'status': 'healthy',
                    'timestamp': timezone.now().isoformat(),
                    'checks': {
                        'database': 'ok',
                        'cache': 'ok' if cache_status else 'error',
                        'celery': 'ok' if celery_status else 'error'
                    }
                }
                
                status_code = 200
                if not cache_status or not celery_status:
                    health_data['status'] = 'degraded'
                    status_code = 503
                
                return JsonResponse(health_data, status=status_code)
                
            except Exception as e:
                return JsonResponse({
                    'status': 'unhealthy',
                    'timestamp': timezone.now().isoformat(),
                    'error': str(e)
                }, status=503)
        
        return None
    
    def check_celery(self):
        """检查Celery状态"""
        try:
            from celery import current_app
            inspect = current_app.control.inspect()
            stats = inspect.stats()
            return bool(stats)
        except Exception:
            return False
